package com.zrkizzy.module.system.service.dict;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zrkizzy.common.core.utils.IdUtil;
import com.zrkizzy.common.core.utils.StringUtil;
import com.zrkizzy.common.core.utils.bean.BeanCopyUtil;
import com.zrkizzy.common.models.domain.system.dict.DictData;
import com.zrkizzy.common.models.domain.system.dict.DictType;
import com.zrkizzy.common.models.dto.system.dict.DictTypeDTO;
import com.zrkizzy.common.models.dto.system.dict.DictTypeOptionDTO;
import com.zrkizzy.common.models.query.system.dict.DictTypeQuery;
import com.zrkizzy.common.models.vo.system.dict.DictDataOptionVO;
import com.zrkizzy.common.models.vo.system.dict.DictTypeOptionVO;
import com.zrkizzy.common.redis.enums.RedisKey;
import com.zrkizzy.common.redis.service.IRedisService;
import com.zrkizzy.module.system.exception.DictErrorCode;
import com.zrkizzy.module.system.mapper.dict.DictDataMapper;
import com.zrkizzy.module.system.mapper.dict.DictTypeMapper;
import com.zrkizzy.system.facade.service.dict.IDictTypeService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 字典类型业务逻辑接口实现类
 * </p>
 *
 * @author zhangrongkang
 * @since 2024/1/16
 */
@Service
@Slf4j
public class DictTypeServiceImpl implements IDictTypeService {

    @Autowired
    private IdUtil idUtil;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private DictTypeMapper dictTypeMapper;

    @Autowired
    private DictDataMapper dictDataMapper;

    /**
     * 项目启动时加载字典数据
     */
    @PostConstruct
    public void init() {
        reloadDictCache();
        log.info("load dict data success");
    }

    /**
     * 获取所有字典类型
     *
     * @param dictTypeQuery 字典类型查询对象
     * @return 字典类型分页数据
     */
    @Override
    public Page<DictType> listDictTypes(DictTypeQuery dictTypeQuery) {
        // 开启分页
        Page<DictType> page = new Page<>(dictTypeQuery.getCurrentPage(), dictTypeQuery.getPageSize());
        QueryWrapper<DictType> queryWrapper = getDictTypeQueryWrapper(dictTypeQuery);
        // 查询分页
        return dictTypeMapper.selectPage(page, queryWrapper);
    }

    /**
     * 定义字典类型查询条件
     *
     * @param dictTypeQuery 字典类型查询对象
     * @return 查询条件
     */
    private QueryWrapper<DictType> getDictTypeQueryWrapper(DictTypeQuery dictTypeQuery) {
        // 定义查询条件
        QueryWrapper<DictType> queryWrapper = new QueryWrapper<>();
        // 字典名称
        if (StringUtil.isNoneBlank(dictTypeQuery.getDictName())) {
            queryWrapper.like("dict_name", dictTypeQuery.getDictName());
        }
        // 字典类型
        if (StringUtil.isNoneBlank(dictTypeQuery.getDictType())) {
            queryWrapper.like("dict_type", dictTypeQuery.getDictType());
        }
        if (Objects.nonNull(dictTypeQuery.getStatus())) {
            // 状态（1 正常 0 停用）
            queryWrapper.eq("status", dictTypeQuery.getStatus());
        }
        // 获取时间范围
        List<String> dataRange = dictTypeQuery.getDataRange();
        // 如果时间范围不为空
        if (!CollectionUtils.isEmpty(dataRange)) {
            // 拼接时间范围查询条件
            queryWrapper.between("create_time", dataRange.get(0), dataRange.get(1));
        }
        return queryWrapper;
    }

    /**
     * 添加或更新字典类型
     *
     * @param dictTypeDTO 字典类型数据接收对象
     * @return 是否添加/更新成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveDictType(DictTypeDTO dictTypeDTO) {
        // 先删除缓存的字典
        Long dictTypeId = dictTypeDTO.getId();
        // 删除对应缓存
        deleteCacheById(dictTypeId);
        // 根据是否包含ID来判断添加-更新操作
        return Objects.nonNull(dictTypeId) ? updateDictType(dictTypeDTO) : insertDictType(dictTypeDTO);
    }

    /**
     * 获取指定字典类型信息
     *
     * @param dictTypeId 字典类型ID
     * @return 字典类型数据返回对象
     */
    @Override
    public DictType getDictTypeById(Long dictTypeId) {
        return dictTypeMapper.selectById(dictTypeId);
    }
    
    /**
     * 批量删除字典类型数据
     *
     * @param ids 字典类型ID
     * @return true：删除成功，false：删除失败
     */
    @Override
    public Boolean deleteBatch(List<Long> ids) {
        // 删除对应的字典数据
        dictDataMapper.deleteByDictTypeIds(ids);
        // 删除对应缓存
        for (Long dictTypeId : ids) {
            deleteCacheById(dictTypeId);
        }
        return dictTypeMapper.deleteBatchIds(ids) == ids.size();
    }

    /**
     * 获取字典选项
     *
     * @return 字典选项集合
     */
    @Override
    public List<DictTypeOptionVO> listOption() {
        return dictTypeMapper.listOption();
    }

    /**
     * 通过字典类型ID删除字典缓存
     *
     * @param dictTypeId 字典类型ID
     */
    @Override
    public void deleteCacheById(Long dictTypeId) {
        // 获取到Redis中存储的缓存类型
        String dictType = dictTypeMapper.getDictTypeById(dictTypeId);
        deleteCacheByType(dictType);
    }

    /**
     * 根据字典类型删除字典缓存
     *
     * @param dictType 字典类型
     */
    @Override
    public void deleteCacheByType(String dictType) {
        String redisKey = RedisKey.DICT_KEY.getKey() + dictType;
        redisService.del(redisKey);
    }

    /**
     * 根据字典类型获取对应字典类型ID
     *
     * @param dictType 字典类型
     * @return 字典类型ID
     */
    @Override
    public Long getDictTypeIdByType(String dictType) {
        return dictTypeMapper.getDictTypeIdByType(dictType);
    }

    /**
     * 重新加载字典缓存
     */
    @Override
    public void reloadDictCache() {
        // 清除所有缓存中的字典类型数据
        clearDictCache();
        loadDictCache();
    }

    /**
     * 清除字典缓存
     */
    @Override
    public void clearDictCache() {
        redisService.clearKeys(RedisKey.DICT_KEY.getKey());
    }

    /**
     * 加载数据字典
     */
    @Override
    public void loadDictCache() {
        // 获取所有可用字典类型
        List<DictTypeOptionDTO> dictTypeOptionList = dictTypeMapper.listDictTypeOption();
        for (DictTypeOptionDTO dictTypeOption : dictTypeOptionList) {
            // 数据库中查询字典数据并存储到Redis
            QueryWrapper<DictData> queryWrapper = new QueryWrapper<DictData>()
                    .eq("dict_type_id", dictTypeOption.getDictTypeId())
                    .eq("status", true)
                    .orderByAsc("sort");
            List<DictDataOptionVO> result = BeanCopyUtil.copyList(dictDataMapper.selectList(queryWrapper), DictDataOptionVO.class);
            redisService.setList(RedisKey.DICT_KEY.getKey() + dictTypeOption.getDictType(), result);
        }
    }

    /**
     * 更新当前字典类型
     *
     * @param dictTypeDTO 字典类型数据接收对象
     * @return 是否更新成功
     */
    private Boolean updateDictType(DictTypeDTO dictTypeDTO) {
        // 对字典类型进行更新操作并返回响应结果
        return dictTypeMapper.updateById(BeanCopyUtil.copy(dictTypeDTO, DictType.class)) == 1;
    }
    
    /**
     * 添加新的字典类型
     *
     * @param dictTypeDTO 字典类型数据接收对象
     * @return 是否添加成功
     */
    private Boolean insertDictType(DictTypeDTO dictTypeDTO) {
        // 判断当前字典类型值是否唯一
        String dictType = dictTypeDTO.getDictType();
        // 校验唯一
        if (dictTypeMapper.selectCount(new QueryWrapper<DictType>().eq("dict_type", dictType)) > 0) {
            // 抛出字典类型已存在异常
            throw DictErrorCode.DICT_TYPE_ALREADY_EXIST.exception();
        }
        // 生成字典类型ID
        Long id = idUtil.nextId();
        // 设置ID
        dictTypeDTO.setId(id);
        // 添加字典类型数据并返回添加结果
        return dictTypeMapper.insert(BeanCopyUtil.copy(dictTypeDTO, DictType.class)) == 1;
    }

}
